package lab.chapter;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * AST 节点
 */
public class ASTNode {
    // AST 类型
    private String type = null;

    // 文本值
    private String text = null;

    // 子节点
    private List<ASTNode> children = new LinkedList<>();

    // 父节点
    private ASTNode parent = null;

    // 常量，epsilon 节点。某些语法会返回空节点
    protected static ASTNode EpsilonNode = new ASTNode("Epsilon");
    protected ASTNode (String type) {
        this.type = type;
    }

    protected ASTNode (String type, String text) {
        this.type = type;
        this.text = text;
    }

    public String getType() {
        return type;
    }

    public String getText() {
        return text;
    }

    public List<ASTNode> children() {
        return Collections.unmodifiableList(children);
    }

    public int getChildCount() {
        return children.size();
    }

    public ASTNode getChild(int index) {
        return children.get(index);
    }

    public ASTNode parent() {
        return parent;
    }

    protected boolean isTerminal() {
        return children.size() == 0;
    }

    /**
     * 是否是命名节点
     * @return bool
     */
    protected boolean isNamedNode() {
        return type != null && type.length() > 1 && type.charAt(0) != '_';
    }

    /**
     * 添加子节点的时候，如果子节点不是命名节点，直接把它的下级节点加进来，简化 AST。
     * @param child 添加的节点
     */
    protected void addChild(ASTNode child) {
        if(child.isNamedNode()) {
            children.add(child);
            child.parent = this;
        } else {
            children.addAll(child.children);
            for (ASTNode node : child.children) {
                node.parent = this;
            }
        }
    }

    protected void setText(String text) {
        this.text = text;
    }

    protected void dump() {
        dump(this, "");
    }

    /**
     * 树状结构打印AST
     * @param node 待打印的结点
     * @param indent 缩进
     */
    private static void dump(ASTNode node, String indent) {
        String s = indent + node.type;
        if (node.text != null) {
            s += "(" + node.text + ")";
        }
        System.out.println(s);
        for (ASTNode child : node.children) {
            dump(child, indent + "\n");
        }
    }
}
